package core

import (
	"errors"
	"lan-file-transfer/models"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// FileManager 文件管理器
type FileManager struct {
	files  sync.Map    // key: fileID, value: *models.FileInfo
	mu     sync.RWMutex
	filter *FileFilter // 文件过滤器
}

// NewFileManager 创建文件管理器
func NewFileManager() *FileManager {
	return &FileManager{
		filter: NewFileFilter(),
	}
}

// GetFilter 获取文件过滤器
func (fm *FileManager) GetFilter() *FileFilter {
	return fm.filter
}

// AddFile 添加单个文件
func (fm *FileManager) AddFile(filePath string) (*models.FileInfo, error) {
	info, err := os.Stat(filePath)
	if err != nil {
		return nil, err
	}

	fileInfo := &models.FileInfo{
		ID:        GenerateUUID(),
		Name:      filepath.Base(filePath),
		Path:      filePath,
		Size:      info.Size(),
		Type:      "file",
		CreatedAt: time.Now(),
		Children:  nil,
	}

	// 计算MD5(在后台异步计算)
	go func() {
		md5, err := CalculateMD5(filePath)
		if err == nil {
			fileInfo.MD5 = md5
		}
	}()

	fm.files.Store(fileInfo.ID, fileInfo)
	return fileInfo, nil
}

// AddDirectory 添加文件夹(递归扫描,带过滤)
func (fm *FileManager) AddDirectory(dirPath string) (*models.FileInfo, error) {
	info, err := os.Stat(dirPath)
	if err != nil {
		return nil, err
	}

	if !info.IsDir() {
		return nil, errors.New("路径不是文件夹")
	}

	dirInfo := &models.FileInfo{
		ID:        GenerateUUID(),
		Name:      filepath.Base(dirPath),
		Path:      dirPath,
		Type:      "directory",
		CreatedAt: time.Now(),
		Children:  make([]*models.FileInfo, 0),
	}

	// 用于存储每个子文件夹的大小映射(相对路径 -> 大小)
	dirSizeMap := make(map[string]int64)

	// 递归扫描文件夹
	err = filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return nil // 跳过错误
		}

		// 跳过根目录
		if path == dirPath {
			return nil
		}

		// 使用过滤器检查是否应该排除
		if fm.filter.ShouldExclude(path, info.IsDir()) {
			if info.IsDir() {
				return filepath.SkipDir // 跳过整个目录
			}
			return nil // 跳过文件
		}

		// 计算相对路径
		relPath, _ := filepath.Rel(dirPath, path)

		if info.IsDir() {
			child := &models.FileInfo{
				ID:        GenerateUUID(),
				Name:      relPath,
				Path:      path,
				Type:      "directory",
				Size:      0, // 稍后填充
				CreatedAt: time.Now(),
			}
			dirInfo.Children = append(dirInfo.Children, child)
		} else {
			child := &models.FileInfo{
				ID:        GenerateUUID(),
				Name:      relPath,
				Path:      path,
				Size:      info.Size(),
				Type:      "file",
				CreatedAt: time.Now(),
			}
			dirInfo.Size += info.Size()
			dirInfo.Children = append(dirInfo.Children, child)

			// 累加文件大小到所有父文件夹
			parentDir := filepath.Dir(relPath)
			for parentDir != "." {
				dirSizeMap[parentDir] += info.Size()
				parentDir = filepath.Dir(parentDir)
			}

			// 异步计算MD5
			go func(p string, c *models.FileInfo) {
				md5, err := CalculateMD5(p)
				if err == nil {
					c.MD5 = md5
				}
			}(path, child)
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	// 填充子文件夹的大小
	for _, child := range dirInfo.Children {
		if child.Type == "directory" {
			child.Size = dirSizeMap[child.Name]
		}
	}

	fm.files.Store(dirInfo.ID, dirInfo)
	return dirInfo, nil
}

// RemoveFile 移除文件
func (fm *FileManager) RemoveFile(fileID string) error {
	_, exists := fm.files.Load(fileID)
	if !exists {
		return errors.New("文件不存在")
	}

	fm.files.Delete(fileID)
	return nil
}

// GetFile 获取文件信息
func (fm *FileManager) GetFile(fileID string) (*models.FileInfo, error) {
	value, exists := fm.files.Load(fileID)
	if !exists {
		return nil, errors.New("文件不存在")
	}

	return value.(*models.FileInfo), nil
}

// GetAllFiles 获取所有文件列表
func (fm *FileManager) GetAllFiles() []*models.FileInfo {
	var files []*models.FileInfo

	fm.files.Range(func(key, value interface{}) bool {
		files = append(files, value.(*models.FileInfo))
		return true
	})

	return files
}

// Clear 清空所有文件
func (fm *FileManager) Clear() {
	fm.files.Range(func(key, value interface{}) bool {
		fm.files.Delete(key)
		return true
	})
}

// GetTotalSize 获取所有文件总大小
func (fm *FileManager) GetTotalSize() int64 {
	var total int64

	fm.files.Range(func(key, value interface{}) bool {
		info := value.(*models.FileInfo)
		total += info.Size
		return true
	})

	return total
}

// GetFileCount 获取文件总数
func (fm *FileManager) GetFileCount() int {
	count := 0
	fm.files.Range(func(key, value interface{}) bool {
		count++
		return true
	})
	return count
}
